#!/usr/bin/python
import os, sys, shutil, string
import AST
import bsvgen
import xpsgen
import cppgen
import syntax
import argparse
import util

AST.Function.__bases__ += (cppgen.NoCMixin,)
AST.Module.__bases__ += (cppgen.NoCMixin,)
AST.Method.__bases__ += (cppgen.MethodMixin,bsvgen.MethodMixin)
AST.StructMember.__bases__ += (cppgen.StructMemberMixin,)
AST.Struct.__bases__ += (cppgen.StructMixin,bsvgen.NullMixin)
AST.EnumElement.__bases__ += (cppgen.EnumElementMixin,)
AST.Enum.__bases__ += (cppgen.EnumMixin,bsvgen.NullMixin)
AST.Type.__bases__ += (cppgen.TypeMixin,bsvgen.TypeMixin)
AST.Param.__bases__ += (cppgen.ParamMixin,)
AST.Interface.__bases__ += (cppgen.InterfaceMixin,bsvgen.InterfaceMixin,xpsgen.InterfaceMixin)

argparser = argparse.ArgumentParser("Generate C++/BSV/Xilinx stubs for an interface.")

argparser.add_argument('bsvfile', help='BSV files to parse', nargs='+')
argparser.add_argument('-b', '--interface', help='BSV interface to generate stubs for')
argparser.add_argument('-p', '--project-dir', default='./xpsproj', help='xps project directory')
argparser.add_argument('-e', '--edk-version', default=xpsgen.edkversion, help='Xilinx EDK version', choices=xpsgen.edkversions)

makefileTemplate='''
BSVPATH = %(bsvpath)s
vfile=pcores/%(corename)s/hdl/verilog/mk%(Dut)sWrapper.v
paofile=pcores/%(corename)s/data/%(dut)s_v2_1_0.pao

$(vfile): pcores/%(corename)s/hdl/verilog/%(Dut)sWrapper.bsv
	cd pcores/%(corename)s/hdl/verilog; bsc -show-schedule -p +:$(BSVPATH) -verilog -u -g mk%(Dut)sWrapper %(Dut)sWrapper.bsv

%(dut)s.make: %(dut)s.xmp
	xps %(dut)s.xmp

verilog: $(vfile)
	./updatepao $(vfile) $(paofile) $(BSVPATH)

netlist: pcores/%(corename)s/hdl/verilog/mk%(Dut)sWrapper.v %(dut)s.make
	make -f %(dut)s.make netlist

implementation/%(dut)s.bit: pcores/%(corename)s/hdl/verilog/mk%(Dut)sWrapper.v %(dut)s.make
	make -f %(dut)s.make bits

bits: implementation/%(dut)s.bit

boot.bin: implementation/%(dut)s.bit
	if [ -f boot.bin ]; then mv -v boot.bin boot.bin.bak; fi
	bootgen -image %(dut)s.bif -o i boot.bin
'''

if __name__=='__main__':
    namespace = argparser.parse_args()
    print namespace

    project_dir = os.path.expanduser(namespace.project_dir)

    for inputfile in namespace.bsvfile:
        s = open(inputfile).read() + '\n'
        s1 = syntax.parse(s)

    corename = '%s_v1_00_a' % namespace.interface.lower()

    makename = os.path.join(project_dir, 'Makefile')
    xmpname = os.path.join(project_dir, '%s.xmp' % namespace.interface.lower())
    mhsname = os.path.join(project_dir, '%s.mhs' % namespace.interface.lower())

    applicationmkname = os.path.join(project_dir, 'jni', 'Application.mk')
    androidmkname = os.path.join(project_dir, 'jni', 'Android.mk')
    hname = os.path.join(project_dir, 'jni', '%s.h' % namespace.interface)
    cppname = os.path.join(project_dir, 'jni', '%s.cpp' % namespace.interface)
    bsvname = os.path.join(project_dir, 'pcores', corename, 'hdl', 'verilog',
                           '%sWrapper.bsv' % namespace.interface)
    vhdname = os.path.join(project_dir, 'pcores', corename, 'hdl', 'vhdl',
                           '%s.vhd' % namespace.interface)
    mpdname = os.path.join(project_dir, 'pcores', corename, 'data',
                           '%s_v2_1_0.mpd' % namespace.interface.lower())
    paoname = os.path.join(project_dir, 'pcores', corename, 'data',
                           '%s_v2_1_0.pao' % namespace.interface.lower())
    ucfname = os.path.join(project_dir, 'data',
                           '%s.ucf' % namespace.interface.lower())
    bifname = os.path.join(project_dir, 
                           '%s.bif' % namespace.interface.lower())
    print 'Writing CPP header', hname
    h = util.createDirAndOpen(hname, 'w')
    h.write('#include "portal.h"\n')
    print 'Writing CPP wrapper', cppname
    cpp = util.createDirAndOpen(cppname, 'w')
    cpp.write('#include "%s.h"\n' % namespace.interface)
    print 'Writing BSV wrapper', bsvname
    bsv = util.createDirAndOpen(bsvname, 'w')
    bsvgen.emitPreamble(bsv, namespace.bsvfile)

    ## code generation pass
    for v in syntax.globaldecls:
        #v.emitCDeclaration(h)
        #v.emitCImplementation(cpp)
        pass
    if (syntax.globalvars.has_key(namespace.interface)):
        subinterface = syntax.globalvars[namespace.interface]

        for d in subinterface.decls:
            if d.type == 'Interface':
                if syntax.globalvars.has_key(d.name):
                    subintdef = syntax.globalvars[d.name]
                    print d.params
                    newint = subintdef.instantiate({'a': d.params[0]})
                    print newint
                    for sd in newint.decls:
                        sd.name = '%s.%s' % (d.name, sd.name)
                        subinterface.decls.append(sd)

        subinterface.emitCDeclaration(h)
        subinterface.emitCImplementation(cpp)

        subinterface.emitBsvImplementation(bsv)
        subinterface.writeMpd(mpdname)
        subinterface.writeMhs(mhsname)
        subinterface.writeXmp(xmpname)
        subinterface.writePao(paoname)
        subinterface.writeVhd(vhdname)
        subinterface.writeUcf(ucfname)
        subinterface.writeBif(bifname)
        print 'Writing Android.mk', androidmkname
        print 'Writing Application.mk', applicationmkname
        subinterface.writeAndroidMk(androidmkname, applicationmkname)

    if cppname:
        srcdir = os.path.join(os.path.dirname(sys.argv[0]), 'cpp')
        dstdir = os.path.dirname(cppname)
        for f in ['portal.h', 'portal.cpp']:
            shutil.copyfile(os.path.join(srcdir, f), os.path.join(dstdir, f))
    shutil.copyfile(os.path.join(os.path.dirname(sys.argv[0]), 'updatepao'),
                    os.path.join(project_dir, 'updatepao'))
    shutil.copymode(os.path.join(os.path.dirname(sys.argv[0]), 'updatepao'),
                    os.path.join(project_dir, 'updatepao'))

    print 'Writing Makefile', makename
    make = util.createDirAndOpen(makename, 'w')
    make.write(makefileTemplate % {'corename': corename,
                                   'dut': namespace.interface.lower(),
                                   'Dut': util.capitalize(namespace.interface),
                                   'bsvpath': os.path.dirname(namespace.bsvfile[0])
                                   })

    print '############################################################'
    print '## To build:'
    print '    cd %s; make bits' % (project_dir)
    print '## You can use XPS to generate bit file or exit and let make complete the process.'
